Proxy
chenpeng 2020-11-30 ES6 API
# 1.概念
Proxy 意为代理,在目标对象之前设置一层拦截,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,对外界的访问可以进行过滤和改写
# 2.声明 Proxy
let proxy = new Proxy(target, handler);
1
Proxy 构造函数中有两个参数:
- target:使用 Proxy 包装的代理对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)
- handler:也是一个对象,用来定制拦截行为
# 3.Proxy 中的处理方法
| 方法 | 描述 |
|---|---|
| get | 获取某个 key 值 |
| set | 设置某个 key 值 |
| has | 使用 in 操作符判断某个 key 是否存在 |
| apply | 函数调用,仅在代理对象为 function 时有效 |
| ownKeys | 获取目标对象所有的 key |
| construct | 函数通过实例化调用,仅在代理对象为 function 时有效 |
| isExtensible | 判断对象是否可扩展,Object.isExtensible 的代理 |
| deleteProperty | 删除一个 property |
| defineProperty | 定义一个新的 property |
| getPrototypeOf | 获取原型对象 |
| setPrototypeOf | 设置原型对象 |
| preventExtensions | 设置对象为不可扩展 |
| getOwnPropertyDescriptor | 获取一个自有属性(不会去原型链查找)的属性描述 |
get() 方法
get() 方法用于获取某对象属性值时的预处理,接受两个常用参数:
- target:目标对象
- key:被获取的属性名
示例:
const person = {
firstName: 'zhang',
lastName: 'san',
};
let handler = {
get(target, key){
if(key === 'fullName'){
return `${target.firstName} ${target.lastName}`
}
}
};
let proxy = new Proxy(person, handler);
console.log(proxy.fullName); // zhang san
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
set() 方法
set() 方法用于拦截某个属性的赋值操作,接受四个参数:
- target:代理对象
- key:被设置的属性名
- value:新属性值
- receiver:最初被调用的对象。通常是 proxy 本身,但 handler 的 set 方法也有可能在原型链上,或以其他方式被间接地调用(因此不一定是 proxy 本身)
示例:
const person = {
age: 20,
};
let handler = {
set(target, key, value){
if(key === 'age'){
if(value >150 || value < 0){
throw new Error('The age seems invalid');
}
}
}
};
let proxy = new Proxy(person, handler);
proxy.age = '-1';
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 4.Proxy 中的 this 指向
一旦 Proxy 代理了 target,target 内部的 this 就指向了 Proxy,而不是 target;有些原生对象的内部属性,只有通过正确的 this 才能拿到,所以 Proxy 无法代理这些原生对象的属性,可以通过 this 绑定 target 来解决这个问题
const target = new Date();
const handler = {
get(target, key) {
if (prop === 'getMonth') {
return target.getMonth.bind(target);
}
return Reflect.get(target, key);
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.getMonth()) // 6
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 6.Proxy 相比 Object.defineProperty 的优势
- 支持数组
const arr = [1,2,3];
let proxy = new Proxy(arr, {
get(target, key, receiver){
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver){
return Reflect.set(target, key, value, receiver);
}
});
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
Proxy 不需要对数组的方法进行重载,省去了众多 hack
针对对象
在数据劫持这个问题上,Proxy 可以被认为是 Object.defineProperty() 的升级版。外界对某个对象的访问,都必须经过这层拦截。因此它是针对整个对象,而不是对象的某个属性,所以也就不需要对 keys 进行遍历
proxy 有多达13种监听方法